from typing import Any, Optional, Dict

from fastapi.exceptions import HTTPException, RequestValidationError
from starlette import status
from starlette.requests import Request
from starlette.responses import JSONResponse


class NormalException(HTTPException):
    """
    normal exception 截获异常后仅将异常代码放入正文 content 中，
    """
    def __init__(
            self,
            status_code: int,
            detail: Any = None,
            headers: Optional[Dict[str, Any]] = None,
    ) -> None:
        super().__init__(status_code=200, detail=detail, headers=headers)
        self.content_code = status_code


async def normal_exception_handler(request: Request, exc: NormalException):
    return JSONResponse(
        {"msg": exc.detail, "code": exc.content_code, "data": None},
        status_code=exc.status_code,
        headers=exc.headers
    )


async def validation_exception_handler(request: Request, exc: RequestValidationError):
    content = {
        "code": 422,
        "msg": "入参异常",
        "data": exc.errors() if isinstance(exc.errors(), dict) else str(exc.errors())
    }
    return JSONResponse(content=content, status_code=status.HTTP_422_UNPROCESSABLE_ENTITY)


exception_handlers = {
    NormalException: normal_exception_handler,
    RequestValidationError: validation_exception_handler
}


class ProtocolError(Exception):
    def __init__(self, message):
        self.message = message

    def __str__(self):
        return f"通讯失败：{self.message}"